package com.gcloud.mesh.distributedSchedule.application;

import java.util.HashMap;

import com.gcloud.mesh.distributedSchedule.AppStatus;
import com.gcloud.mesh.distributedSchedule.ClusterAvailableResource;
import com.gcloud.mesh.distributedSchedule.IApplication;
import com.gcloud.mesh.distributedSchedule.ICluster;

// 时间序列数据记录到数据库
// 监控系统监控到数据，记录到数据库并提交到本类实例
public class CommonApplication extends Application implements IApplication {

    // recent resource cost.
    private double recentMemSpace;
    private int recentStorageSpace;
    private int recentBandWidthKBPS;
    private int recentCpuCores;

    // 爆发最高点
    private double burstMemSpace;
    private int burstStorageSpace;
    private int burstBandWidthKBPS;

    // 平均值
    private int updateCount = 0;   // status update time
    private double averageMemSpace;
    private int averageStorageSpace;
    private int averageBandWidthKBPS;
    private int averageCpuCoresCost;


    private long startTime;
    private long endTime;

    public CommonApplication(String appName, String appId) {
        this.setAppId(appId);
        this.setAppName(appName);
    }

    @Override
    public void init(int cpuCore, double memSpaceG, int storageSpaceG, int bandWidthKBPS) {
        this.cpuCores = cpuCore;
        this.memSpace = memSpaceG;
        this.storageSpace = storageSpaceG;
        this.bandWidthKBPS = bandWidthKBPS;
    }

    @Override
    public void updateStatus(int cpuCore, double memSpaceG, int storageSpaceG, int bandWidthKBPS) {
        // 记录资源消耗峰值
        if (memSpaceG > this.burstMemSpace) this.burstMemSpace = memSpaceG;
        if (storageSpaceG > this.burstStorageSpace) this.burstStorageSpace = storageSpaceG;
        if (bandWidthKBPS > this.burstBandWidthKBPS) this.burstBandWidthKBPS = bandWidthKBPS;

        // 计算资源消耗均值
        this.averageMemSpace = (this.averageMemSpace * this.updateCount + memSpaceG) / (this.updateCount + 1);
        this.averageStorageSpace = (this.averageStorageSpace * this.updateCount + storageSpaceG) / (this.updateCount + 1);
        this.averageBandWidthKBPS = (this.averageBandWidthKBPS * this.updateCount + bandWidthKBPS) / (this.bandWidthKBPS + 1);

        // 记录最新更新值
        this.recentBandWidthKBPS = bandWidthKBPS;
        this.recentCpuCores = cpuCore;
        this.recentMemSpace = memSpaceG;
        this.recentStorageSpace = storageSpaceG;

        this.updateCount++;

        // TODO: improve this...
        this.LSTM(cpuCore, memSpaceG, storageSpaceG, bandWidthKBPS);
    }

    @Override
    public AppStatus getStatus() {
        // TODO: 返回app实际的资源消耗情况，这里用统计平均值来表示，可以根据实际情况调整，比如引入ML来预测
        return new AppStatus(this.averageCpuCoresCost,
                this.averageMemSpace,
                this.averageStorageSpace,
                this.averageBandWidthKBPS);
    }

    @Override
    public void appStartTime(long startTime) {
        if (startTime > 0)
            this.startTime = startTime;
        else
            this.startTime = System.currentTimeMillis();
    }

    @Override
    public void appEnd() {
        this.endTime = System.currentTimeMillis();
    }

    @Override
    public String getId() {
        return super.getAppId();
    }

    @Override
    public String getName() {
        return super.getAppName();
    }

    @Override
    public String getClusterId() {
        return super.getClusterId();
    }

    public void setClusterId(String id) {
        super.setClusterId(id);
    }

    /**
     * 判断有很多种标准，可以以标准值来判断，可以用平均值来判断，也可以用峰值来判断，安全起见，这里用峰值
     * @return true or false
     */
    @Override
    public boolean isResourceSatisfied(ClusterAvailableResource availRes) {
        return availRes.getAvailBandWidth() > this.burstBandWidthKBPS &&
                availRes.getAvailMemSpace() > this.burstMemSpace &&
                availRes.getAvailStorageSpace() > this.burstStorageSpace;
    }

    /**
     * 迁移代价评估，要综合评估已有外部存储的规模、当前应用的状态，包括内存使用，IO情况等，
     * 以衡量停止和迁移应用的代价
     * @param cluster 应用所在的集群
     * @return 迁移代价数值
     */
    @Override
    public int migrateCost(ICluster cluster) {
        // TODO:
        return 0;
    }

    /** TODO:
     * 本应用绑定在哪个集群上，不绑定则为空；绑定了表示不能迁移
     */
    private String stickClusterId = "";
    public String getStickedClusterId() { return this.stickClusterId; }
    public void setStickedClusterId(String clusterId) { this.stickClusterId = clusterId; }

    /** TODO:
     * 本应用亲和的其他应用，亲和指的是必须在同一个集群，因此如果要调度则必须所有亲和的应用一起调度
     */
    private HashMap<String, IApplication> affineApp = null;
    public void setAffinityApp(HashMap<String, IApplication> apps) {
        this.affineApp = apps;
    }
    public HashMap<String, IApplication> getAffinityApp() {
        return this.affineApp;
    }

    /** TODO:
     * 本应用排斥的其他应用，排斥指的是不能部署在同一个集群
     */
    private HashMap<String, IApplication> repulsiveApp = null;
    public void setRepulsiveApp(HashMap<String, IApplication> apps) {
        this.repulsiveApp = apps;
    }
    public HashMap<String, IApplication> getRepulsiveApp() {
        return this.repulsiveApp;
    }

    private void LSTM(int cpuCores, double memSpace, int storageSpace, int bandWidthKBPS) {
        // TODO: lstm ML to predicting resource consumption in next stage....
        // store ML module into DB...
    }
}
